#pragma once

#include "log.hpp"
#include "epoller.hpp"
#include "nocopy.hpp"
#include "Socket.hpp"
#include "Comm.hpp"

#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include <unordered_map>
#include <cerrno>

class Connection;
class TcpServer;
using func_t = std::function<void(std::shared_ptr<Connection>)>;

class Connection
{
public:
    Connection(int sockfd, std::shared_ptr<TcpServer> tcp_server_ptr)
        : _sockfd(sockfd), _tcp_server_ptr(tcp_server_ptr)
    {
    }
    void SetHandler(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }
    int Fd()
    {
        return _sockfd;
    }
    void Append(const std::string &info)
    {
        _inbuffer += info;
    }
    ~Connection()
    {
    }

private:
    int _sockfd;
    // 用string充当缓冲区，但无法处理二进制流
    std::string _inbuffer;  // 接收缓冲区
    std::string _outbuffer; // 发送缓冲区
public:
    func_t _recv_cb;   // 读回调
    func_t _send_cb;   // 写回调
    func_t _except_cb; // 异常回调

    std::string _ip;
    uint16_t _port;

private:
    // 指向TcpServer的回指指针
    std::shared_ptr<TcpServer> _tcp_server_ptr;
};

static const uint16_t defaultport = 8082;
uint32_t EVENT_IN = (EPOLLIN | EPOLLET);   // 读事件的值 和 ET模式的值
uint32_t EVENT_OUT = (EPOLLOUT | EPOLLET); //....
static const int num = 64;
static const int g_buffer_size = 4096;

class TcpServer : Nocopy
{
public:
    TcpServer(const uint16_t port = defaultport, func_t OnMessage)
        : _epoller_ptr(new Epoller()), _listen_sockfd_ptr(new Sock()), _port(port), _isrunning(false), _OnMessage(OnMessage)
    {
    }
    ~TcpServer()
    {
    }

public:
    void InitServer()
    {
        _listen_sockfd_ptr->Socket();
        SetNonBlockOrDie(_listen_sockfd_ptr->Fd()); // 将listen_sockfd的文件描述符设置为非阻塞
        _listen_sockfd_ptr->Bind(_port);
        _listen_sockfd_ptr->Listen();
        ADDConnection(_listen_sockfd_ptr->Fd(), EVENT_IN,
                      std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
    }
    void Loop()
    {
        _isrunning = true;
        // 我们添加对应的事件，除了把fd<->event写入内核，还要在用户层维护一个fd<->Connection
        while (!_isrunning)
        {
        }
        _isrunning = false;
    }

public:
    void ADDConnection(int sockfd, uint32_t event, func_t recv_cb, func_t send_cb, func_t except_cb,
                       const std::string &ip = "0.0.0.0", const uint16_t &port = 0)
    {
        // 1. 写入unordered_map
        std::shared_ptr<Connection> new_connection = std::make_shared<Connection>(sockfd, std::shared_ptr<TcpServer>(this));
        new_connection->SetHandler(recv_cb, send_cb, except_cb);
        new_connection->_ip = ip;
        new_connection->_port = port;

        _connections.insert(std::make_pair(sockfd, new_connection));
        // 1. 写入内核，添加红黑树节点
        _epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD, sockfd, event);
    }
    bool IsConnectionSafe(int fd)
    {
        auto iter = _connections.find(fd);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }
    void Dispatcher(int timeout) // 事件派发
    {
        int n = _epoller_ptr->EpollerWait(revs, num, timeout);
        for (int i = 0; i < n; i++)
        {
            uint32_t events = revs[i].events;
            int sockfd = revs[i].data.fd;

            // 把异常事件转换为读写问题，不需要单独处理异常了，因为异常了之后，读写也一定异常，所以复用读写的处理就可以
            if (events & EPOLLERR)
                events |= (EPOLLIN | EPOLLOUT);
            if (events & EPOLLHUP)
                events |= (EPOLLIN | EPOLLOUT);

            if ((events & EPOLLIN) && IsConnectionSafe(sockfd))
            {
                if (_connections[sockfd]->_recv_cb)
                    _connections[sockfd]->_recv_cb(_connections[sockfd]);
            }
            if ((events & EPOLLOUT) && IsConnectionSafe(sockfd))
            {
                if (_connections[sockfd]->_send_cb)
                    _connections[sockfd]->_send_cb(_connections[sockfd]);
            }
        }
    }

    // 链接管理器
    void Accepter(std::shared_ptr<Connection> connection)
    {
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = ::accept(connection->Fd(), (struct sockaddr *)&peer, &len);
            if (sockfd > 0)
            {
                char ipbuf[64];
                uint16_t peerport = ntohs(peer.sin_port);
                inet_ntop(AF_INET, &peer.sin_addr.s_addr, ipbuf, sizeof(ipbuf));

                SetNonBlockOrDie(sockfd);
                ADDConnection(sockfd, EVENT_IN, std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excepter, this, std::placeholders::_1),
                              ipbuf, peerport);
            }
            else
            {
                if (errno == EWOULDBLOCK)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                    break;
            }
        }
    }
    // 事件管理器
    void Recver(std::shared_ptr<Connection> connection)
    {
        int sockfd = connection->Fd();
        while (true)
        {
            char buffer[g_buffer_size];
            memset(buffer, 0, sizeof(buffer));
            ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                connection->Append(buffer);
            }
            else if (n == 0)
            {
                connection->_except_cb(connection);
            }
            else
            {
                if(errno == EWOULDBLOCK) break;
                else if(errno == EINTR) continue;
                else connection->_except_cb(connection);
            }
        }
        //数据给上层进行处理
        _OnMessage(connection);
    }
    void Sender(std::shared_ptr<Connection> connection)
    {
    }
    void Excepter(std::shared_ptr<Connection> connection)
    {
    }

private:
    std::shared_ptr<Epoller> _epoller_ptr;                             // 内核epoll模型
    std::shared_ptr<Sock> _listen_sockfd_ptr;                          // listen监听套接字
    std::unordered_map<int, std::shared_ptr<Connection>> _connections; // 每个套接字对应的Connection
    struct epoll_event revs[num];                                      // 存放就绪的事件
    uint16_t _port;
    bool _isrunning;

    //让上层处理数据
    func_t _OnMessage;
};